import java.io.BufferedReader
import java.lang.Exception
import java.lang.NumberFormatException
import java.lang.StringBuilder
import java.util.*

/**
 * fun function(方法,函数)
 * main 方法名,主方法和Java一样都是以main命名,是一个关键字
 * args 参数名,是一个main方法的形参
 * Array<String> String类型数组,在kotlin中没有[]的表示,一个Array就代表是一个数组
 * 注意,与Java不同,kotlin声明变量的时候,名字在前,类型在后,中间用:表示类型
 * 返回值先不讲,实际与Java类似,也是有无返回值的类型,只是可以省略
 */
fun main(args: Array<String>): Unit {
//    println("Hello,world!")
//    println(max(1, 2))
//    int = 13
//    list.add("kotlin")
//    println(list)
//    list.remove("Java")
//    println(list)
//    list.remove("kotlin")
//    println(list)
//    println("Hello:$name")
//    println("1 + 2 = ${1 + 2}")
//    println("a ${if (a >= 10) "大于等于10" else "小于10"}")
//    println("a ${if (a >= 10) "" else ""}")
//
//    val userJava = UserJava("LC")
//    userJava.password = "345"//赋值调用的就是set方法
//    println("userJava password:${userJava.password}")//取值调用的就是get方法
//
//    val user = User("LC", "123")
//    user.password = "3456"
//    println("user password:${user.password}")
//    val rectangle = Rectangle(12, 13)
//    println("rectangle:是否是个正方形:${rectangle.isSquare}")
//    val rectangleJava = RectangleJava(12, 12)
//    println("rectangleJava:是否是个正方形:${rectangleJava.isSquare}")
//
//    println(rectangle)
//    println(Color.ORANGE.rgb())
//    println(getColorString(Color.ORANGE))
//    println(mix(Color.RED, Color.YELLOW))
//    println(mix(Color.YELLOW, Color.RED))
//    println(mix2(Color.RED, Color.YELLOW))
//    println(mix2(Color.YELLOW, Color.RED))
//    play()
//    binary()
//    println(regex('中'))
//    println(regex('2'))
//    println(regex('A'))
//    println(c)
//    println(list2.javaClass)
//    println(mutableList.javaClass)
//    println(set.javaClass)
//    println(map.javaClass)
//
//    println(list2.last())
//    println(list2)
//    println(joinToString(list2, "||", "{", "}"))
//    println(joinToString(prefix = "::", postfix = "||", collection = list2, separator = "^^"))

//    println(joinToString(list2))
    println("kotlin".lastChar())
    println("专高".lastChar())
}


/**
 * 方法(函数):
 * 有返回值,没有返回值的方法
 * 在kotlin中,其实所有的方法都有返回值,只是没有返回值的方法他的返回值可以省略
 * Unit 相当于Java中void
 * a:Int a 是参数名,:Int是类型 :在kotlin中很重要,有继承实现,类型众多意思
 * 整个方法后的:Int,代表当前方法的返回值是个Int类型
 * 在kotlin中所有的基本类型比如int,boolean都是大写开头
 */
//fun max(a: Int, b: Int): Int {
//    return if (a > b) a else b
//}

/**
 * kotlin特性,表达式方法体(函数体)
 * 如果一个方法的方法体是由单个表达式构成,可以用这个表达式作为完整的方法体,并且去掉大括号和return
 * 同时方法的返回值:Int也是可以省略的
 */
fun max(a: Int, b: Int) = if (a > b) a else b

/**
 * 变量:
 * val (value) 不可变变量,在初始化之后不能再次赋值,对应Java中final修饰符
 * var (variable) 可变变量,这种变量的值是可以改变的,对应Java中的普通变量
 * :String 可以省略,也就是val和var可以自动识别类型,初始化是什么类型,之后使用或者赋值就是什么类型
 * 初始化是一个int,再次赋值时也必须是一个int,不能改变类型,可以改变值
 * 有一个情况比较特殊,使用val声明list的时候,他的集合中的元素是可以被改变的
 */
val str = "这是一个String"
var a = 12

/**
 * 字符串模板(拼接字符串)
 * 使用$符号可以直接在字符串中引用某些变量,甚至可以加{}大括号来机型计算或者判断
 * 注意在写句式的时候,先写出完整的字符串,再加入${} 这样不会乱
 */
val name = "LC"

/**
 * 枚举
 * 在kotlin中唯一一个能用到分号的地方就是枚举
 * 代表换行是一个方法,而不是一个枚举了
 */
enum class Color(val r: Int, val g: Int, val b: Int) {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 0),
    BLUE(0, 0, 255);

    fun rgb() = (r * 256 + g) * 256 + b
}

fun getColorString(color: Color) = when (color) {
    Color.RED -> "红色"
    Color.ORANGE -> "橙色"
    Color.YELLOW -> "黄色"
    Color.GREEN -> "绿色"
    Color.BLUE -> "蓝色"
}

/**
 * 使用when替换if-else
 */
//val b = 2
//var max = when {
//    a > b -> {
//        a
//    }
//    else -> b
//}
//
//var max1 = if (a > b) a else b
//
//fun max2(a: Int, b: Int): Int {
//    return if (a > b) a else b
//}

/**
 * when的特性,可以判断任意对象,比如一个set中的内容都是可以判断的
 */
fun mix(c1: Color, c2: Color) = when (setOf(c1, c2)) {
    setOf(Color.YELLOW, Color.RED) -> "橙色"
    setOf(Color.YELLOW, Color.BLUE) -> "绿色"
    else -> "其他颜色"
}

fun mix2(c1: Color, c2: Color) = when {
    (c1 == Color.RED && c2 == Color.YELLOW) || (c2 == Color.RED && c1 == Color.YELLOW) -> "橙色"
    c1 == Color.YELLOW && c2 == Color.BLUE -> "绿色"
    else -> "其他颜色"
}

/**
 * 区间
 * 1..10 1到10并且包含10, 1 until 10 1到10,但是不包含10
 */
val oneToTen = 1..10
val oneToNine = 1 until 10

fun fizzBuzz(i: Int) = when {
    i % 15 == 0 -> "FizzBuzz"
    i % 5 == 0 -> "Buzz"
    i % 3 == 0 -> "Fizz"
    else -> "$i"
}

/**
 * i 是个形参,些什么都可以,按照for循环的习惯,一般写作i
 * in 在某个区间之内,或者list或者数组,或者区间
 */
val list = arrayListOf("Java")//arrayListOf 相当于new了一个ArrayList
val numList = mutableListOf(1, 2, 3)

fun play() {
    for (index in 1..100) {
        println(fizzBuzz(index))
    }

    list.forEach {
        println(it)
    }

    numList.forEach { num ->
        println(num)
    }
}

fun binary() {
    val binaryReps = TreeMap<Char, String>()//声明了一个map,kv结构,使用TreeMap可以让键排序
    for (char in 'A'..'F') {
        val binary = Integer.toBinaryString(char.toInt())//把A到F的ASCII码转换为二进制
//        binaryReps.put(char, binary)
        binaryReps[char] = binary //根据键char,把值存入map中
    }

    //迭代map
    for ((key, value) in binaryReps) {
        println("$key = $value")
    }

    //.withIndex() 相当于给每一个元素多了一个index的key,element就是他的值
    val list = arrayListOf("10", "11", "1001")
    for ((a, b) in list.withIndex()) {
        println("$a:$b")
    }
}

fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
fun isNumber(c: Char) = c in '0'..'9'

fun regex(c: Char) = when {
    isLetter(c) -> "这是个字母"
    isNumber(c) -> "这是个数字"
    else -> "这可能是个符号,也可能是个中文"
}

/**
 * String? 代表这个声明的对象可以为空
 * 在kotlin中?很重要,代表一个类型是否可以为空,如果声明一个类型可以为空的话,必须要加?
 * 在kotlin中非空对象和可空对象是两种不同类型,比如String和String?是2个不同的类型
 * 非空对象可以给可空对象赋值,也就是c1可以给c2赋值
 * !!代表非空断言,表示这个值一定不为空
 */
var c1: String = "123"
var c2: String? = "123"
var c3: String? = null

fun c22() {
    if (c2 != null) {
        c1 = c2 as String
    }
    c2 = c1
}

var c = if (a > 0) a else throw Exception("这是个负数或者0")

fun redNumber(reader: BufferedReader): Int? = try {
    val line = reader.readLine()
    Integer.parseInt(line)
} catch (e: NumberFormatException) {
    null
} finally {
    reader.close()
}

/**
 * 集合
 * 在kotlin中直接listOf就是创建出一个集合
 * 常用的其实是mutableListOf,创建可变集合
 * to 不是一个特殊的结构,是一个普通的方法,此方法会返回一个键值对,相当于在Java中使用:创建键值对
 */
val mutableList = mutableListOf(1, 2, 3) //可变list
val list2 = listOf(1, 2, 3)//相当于在Java中new了一个list
val set = setOf(1, 2, 3)//set是无序的集合,其中的内容没有index
val map = mapOf(1 to "one", 2 to "two")//相当于new了一个map

/**
 * 命名参数
 * 如果使用了一个命名参数,则其他的参数都必须是命名参数,可以指定参数的位置
 * 与Java不同,kotlin中可以指定参数的位置,不需要一定按照参数顺序去写
 *
 * 参数默认值
 * 默认参数,如果在方法中给了默认参数,则在调用发昂发的时候可以不再次赋值
 * 如果在有默认参数的情况下,再给了新的参数,则按照新的参数赋值
 */
fun <T> joinToString(
    collection: Collection<T>,//集合的顶层接口,代表这个参数可以是list或者set
    separator: String = ".",//分隔符
    prefix: String = "{",//开始的符号
    postfix: String = "}"//结束的符号
): String {
    val result = StringBuilder(prefix)//首先创建一个可拼接的字符串,默认添加开始符号
    for ((index, element) in collection.withIndex()) {
        if (index > 0) {
            result.append(separator)//下标大于0的情况才添加分隔符
        }
        result.append(element)//每次循环在分隔符之后添加一个集合中的元素
    }
    result.append(postfix)//循环结束,在String的末尾添加结束符号
    return result.toString()
}

/**
 * 扩展方法(函数)
 * 给一个已有的类或者类型添加一个方法,在Java中某些类型是不可能办到的,因为final修饰的类无法继承
 */
fun String.lastChar() = this[this.length - 1]